﻿//////////////////////////////////////////////////////////////////////////////
//
//  Copyright © 1998-2024 Glodon Company Limited.  All rights reserved.
//
//  Use of this software is subject to the terms of the Glodon license
//  agreement provided at the time of installation or download, or which
//  otherwise accompanies this software in either electronic or hard copy form.  
//
//////////////////////////////////////////////////////////////////////////////

// Brief: 操作sqlite数据库

#include "GmepComponentUtils.h"

namespace gnuf {
    class GnufProgressBar;
}

namespace gmep
{
    class IGmepPropertyInfo;
    class IGmepCategoryInfo;
}

struct GmepComponent;
struct ComponentInfos;
struct SqlRecordInfo;
struct GmepComponentType;
struct GmepComponentPlaceHolderInfo;
enum class GmepComponentDirtyFlag : int32_t;
struct GacFileInfo;

// 打开工作单元 增量下载构件时写入Sqlite的函数
class GMEP_COMPONENT_UTILS_EXPORT ComponentSqlUtils
{
public:
    /// \brief 长类型名重定义
    /// \author dengb-c@20210203
    typedef typename std::map<std::wstring, const gmep::IGmepCategoryInfo*> mapCategoryInfoType;
    typedef typename std::map<std::wstring, std::vector<GmepComponent>> mapGmepComponentsType;
    typedef typename std::map<std::wstring, ComponentInfos> mapComponentInfosType;
    typedef typename std::map<std::wstring, std::vector<SqlRecordInfo>> mapSqlRecordInfoType;

    static bool LibraryDBFileExists(std::wstring dbFilePath);
    // 添加构件表和构件规格Data表（为某一个category）
    static bool InstertNewTable(const std::wstring& dbFilePath, const std::wstring& strSQLTableName, const std::wstring& strSQLDataTableName,
       const std::map<std::wstring, const gmep::IGmepPropertyInfo *>& stdCodeAndPropMap);

    /// \brief 添加构件行 （为某一个category的所有构件）
    static bool InstertComponentRows(const std::wstring& SQLDbPath, const std::wstring&  strDataTableName, const std::wstring& strSQLDataTableName,
        std::vector<GmepComponent> compList, std::map<std::wstring, const gmep::IGmepPropertyInfo *> stdCodeAndPropMap);

    /// \brief 更新构件行 （为某一个category的所有构件）
    static bool UpdateComponentRows(const std::wstring& SQLDbPath, const std::wstring&  strSQLTableName, const std::wstring& strSQLDataTableName,
        const std::vector<GmepComponent>& compList, const std::map<std::wstring, const gmep::IGmepPropertyInfo *>& stdCodeAndPropMap,
        std::vector<GmepComponent>& updatedCompList);

    /// \brief 创建ComponentId 表，若存在并删除相应category表的构件行； 创建ProductLirary_2D 表
    /// \param SQLDbPath - 数据库路径，缓存目录下；操作数据库必须，故可以不用外部传入
    /// \param deletedComponentIdList - 需要删除的列表
    static bool InsertSpecialTablesAndDeleteComponents(const std::wstring SQLDbPath, std::map<std::wstring, int> deletedComponentIdList);

    /// \brief 根据 构件ID，查询数据库中的版本号，与容器中的版本进行对比，更新容器
    /// \param projectId - 项目ID，为了找到数据库存放地址
    /// \param updateComponentIds - ID与其版本号的容器，如果其版本号与数据库中的版本号不同，则更新；相同则删除
    /// \return 如果返回是负数，则表示出错；返回0，正常
    static int UpdateComponentVersionById(const std::wstring& projectId, std::map<std::wstring, int>& updateComponentIds);

    /// \brief 判断tableName的表是否存在
    /// \param tableName - 需要查询的数据库表名
    /// \return true - 存在； false - 不存在
    static bool IsHasTable(const std::wstring& tableName);

    /// \brief 打开db3 返回是否获取table成功，获取成功时 返回 是否存在该table
    /// \param dbFilePath - 需要查询的数据库路径
    /// \param tableName - 需要查询的数据库表名
    /// \hasTable: true - 存在； false - 不存在
    /// \return true - 成功获取到； false - 未成功获取到
    static bool IsHasTable(const std::wstring& dbFilePath, const std::wstring& tableName, bool& hasTable);

    /// \brief 判断columnName的列是否存在
    /// \param tableName - 需要查询的数据库表名
    /// \param columnName - 需要查询的数据库列名
    /// \return true - 存在； false - 不存在
    static bool IsHasColumn(const std::wstring& tableName, const std::wstring& columnName);

    /// \brief 打开db3 返回是否获取columnName成功，获取成功时 返回 是否存在该columnName
    /// \param dbFilePath - 需要查询的数据库路径
    /// \param tableName - 需要查询的数据库表名
    /// \param columnName - 需要查询的数据库列名
    /// \hasColumn: true - 存在； false - 不存在
    /// \return true - 成功获取到； false - 未成功获取到
    static bool IsHasColumn(const std::wstring& dbFilePath, const std::wstring& tableName, const std::wstring& columnName, bool& hasColumn);

    /// \brief 统一获取，避免频繁打开关闭数据库
    /// \param gmepCategoryList - 构件种类列表
    /// \param retCompList - 所有项目构件信息及数据
    /// \author dengb-c@20210203
    static bool QueryComponentVersion(const mapCategoryInfoType gmepCategoryList, mapGmepComponentsType &retCompList);

    /// \brief 从ComponentId中获取categoryCode
    /// \param localComponentIdList - 本地拷贝构件详情
    /// \author dengb-c@20210311
    static bool QueryComponentCategoryCode(mapComponentInfosType& localComponentIdList, const std::wstring& dbFilePath);

    /// \brief 根据表名，查找其所有的字段信息
    /// \param localComponentIdList - 取其中的表名
    /// \param mapRecordNameByTable - 返回表和其相应的字段名
    /// \author dengb-c@20210314
    static bool QueryRecordNameByTableName(const mapComponentInfosType& localComponentIdList,
        mapSqlRecordInfoType& mapRecordNameByTable);

    /// \brief 根据表名和字段名，查询所有的值
    /// \param mapRecordNameByTable - 表及其字段名
    /// \param wstrLocalId - 本地ID
    /// \param wstrTableName - 需要查询的data表
    /// \param vcCompTypes - 返回的值
    /// \author dengb-c@20210314
    static bool QueryDataTableAllRecord(mapSqlRecordInfoType mapRecordNameByTable, const std::wstring& wstrLocalId,
        const std::wstring& wstrTableName, std::vector<GmepComponentType>& vcCompTypes);

    // 下载指定的二维图例 gac 和 png前调用此函数找出db3不存在id的，返回toSyncPlaceHolderIdInfoMap， 返回已存在的id和name的map
    static void QueryNonExist2DPlaceHolders(const std::wstring& dbFilePath, std::map<std::wstring, GmepComponentPlaceHolderInfo>& toSyncPlaceHolderIdInfoMap,
        std::map<std::wstring, GmepComponentPlaceHolderInfo>& existPlaceHoldersMap);

    static int ExceptFilterFunc(_EXCEPTION_POINTERS* info);
    /// \brief 从本地数据库拷贝数据到缓存数据库中
    /// \param compIdAndInfoMap - 返回表和其相应的字段名
    /// \param srcDbFilePath - 本地数据库目录
    /// \param targetDbFilePath - 目标数据库目录
    /// \param projectFolder - 项目构件文件夹(合并后的gac存放)
    /// \param project3DFolder - 项目三维构件文件夹
    /// \param project2DFolder - 项目二维图例文件夹
    static bool CopyComponentsFromSourceToDB(
        const std::wstring& srcDbFilePath,
        const std::wstring& targetDbFilePath,
        const std::wstring& projectFolder,
        const std::wstring& project3DFolder,
        const std::wstring& project2DFolder,
        mapComponentInfosType& compIdAndInfoMap
    );

    /// \brief 从本地数据库拷贝数据到缓存数据库中
    /// \param srcDbFilePath - 本地数据库目录
    /// \param targetDbFilePath - 目标数据库目录
    /// \param projectFolder - 项目构件文件夹(合并后的gac存放)
    /// \param project3DFolder - 项目三维构件文件夹
    /// \param project2DFolder - 项目二维图例文件夹
    /// \param compIdAndInfoMap - 返回表和其相应的字段名
    static bool CopyComponentsFromSourceToDBMain(
        const std::wstring& srcDbFilePath,
        const std::wstring& targetDbFilePath,
        const std::wstring& projectFolder,
        const std::wstring& project3DFolder,
        const std::wstring& project2DFolder,
        mapComponentInfosType& compIdAndInfoMap);

    /// 20220430从本地安装包拷贝ProductLibrary_2d 文件夹和table, 若从本地成功拷贝， 返回true
    static bool Copy2DProductLibraryFromLocal(const  std::wstring& dbFilePath, const  std::wstring& projectProduct2DFolder);
    /// 月初首次升级db3时，比较缓存和本地db3的ProductLibrary_2d table, 将缓存不存在的条目拷到缓存
    static bool CopyNonExistPlaceHoldersFromLocal(const  std::wstring& dbFilePat);
    /// 从网络下载的图例信息 写到 ProductLibrary_2d  table
    /// forceUpdateResId 为true 则即使存在这行，如果 from来源不一样也强制更新ResourceId 和 spu id
    static bool WriteTo2DProductLibraryTable(const std::wstring& dbFilePath, const std::map<std::wstring, GmepComponentPlaceHolderInfo>& syncedPlaceHolderIdInfoMap,
        std::map<std::wstring, GmepComponentPlaceHolderInfo>& forceUpdatedResPlaceHolderMap, bool forceUpdateResId = false);

    /// 构件修改后存储
    static bool SaveModifiedComponent(
        const std::wstring dbFilePath, const gmep::IGmepCategoryInfo* pCategoryInfo,
        GmepComponent &component);

    /// 构件新增后存储
    static bool SaveAddedComponentsOfOneCategory(const std::wstring dbFilePath, const gmep::IGmepCategoryInfo* pCategory, std::vector<GmepComponent>& compVec);
    static bool SaveRelacedComponentsOfOneCategory(
        const std::wstring dbFilePath, const gmep::IGmepCategoryInfo* pCategory, std::vector<GmepComponent>& compVec);

    //根据构件id删除该构件，判断构建是否需要完全删除从构建的DirtyFlag 的状态进行判断
    // UnChanged -- 改变为 LocalDeleted
    // LocalModified -- 改变为 LocalDeleted
    // LocalAddedFromPublic -- 直接删除
    // LocalAddedFromPublicThenModify -- 直接删除
    // LocalAddedFromGAC -- 直接删除
    // LocalAddedFromGACThenModify -- 直接删除
    static bool SoftDeleteComponentsFromDB(const std::wstring& dbFilePath, const gmep::IGmepCategoryInfo* pCategory, const std::wstring& compId);

    //从数据库中删除构件
    //包含compinentid表 data 表 及构件表
    static bool DeleteDataFormDB(const std::wstring dbPath, const gmep::IGmepCategoryInfo* pCategory, const std::wstring compId,bool isFilterHasModif = false,bool isOpenDatase = true, bool deleteGacFile = false);

    static bool SearchComponentNameIsExistFromDB(const std::wstring dbFilePath, const gmep::IGmepCategoryInfo* pCategoryInfo,GmepComponent &component);

    //如果检测到有名字相同的则在名字后边添加（最大数字）
    static bool SearchComponentNamelikeFromDB(const std::wstring dbFilePath, const gmep::IGmepCategoryInfo* pCategoryInfo, GmepComponent &component,std::wstring& returnName);

    // 更新数据

    // \param[in] dbPath 数据库路径
    // \param[in] tableName 表头
    // \param[in] columnNames 列名
    // \param[in] values 数据(与列名一一对应)
    // \param[in] filter 过滤条件(例:Id = 3)
    // ※※※※※ filter为空时将更新所有行   ※※※※※
    static bool UpdateTableData(const std::wstring dbPath, const std::wstring tableName, const std::map<std::wstring, std::wstring>& columnValueMap,  const std::wstring filter, bool isCloseDb = true);

    // 删除
    // \param[in] dbPath 数据库路径
    // \param[in] tableName 表头
    // \param[in] filter 过滤条件(例:Id = 3)
    // ※※※※※ filter为空时将删除所有行   ※※※※※
    static bool DeleteTableData(const std::wstring dbPath, const std::wstring tableName, const std::wstring filter = nullptr,bool isCloseDb = true);
    
    // 读取数据
    // \param[in] dbPath 数据库路径
    // \param[in] tableName 表头
    // \param[in] columnNames 列名
    // \param[in] filter 过滤条件(例:Id = 3)
    static std::vector<std::vector<std::wstring>> SearchTableList(const std::wstring& dbPath, const std::wstring tableName, const std::vector<std::wstring> columnNames, const std::wstring filter = nullptr,bool isOpenData = true);

    static std::vector<GacFileInfo> SeachGACComponentInfo(const std::wstring& dbFilePath, const std::wstring& projectProduct3DFolder, const std::map<std::wstring, int>& addedFromGACIdVerMap);

    static bool GetLocalProjectComponentCountOfCategory(const std::wstring & dbFilePath, const std::wstring & categoryCode, int& iCount);
    static bool GetLocalProjectComponentCountOfCategory(const std::wstring & dbFilePath, const std::vector<std::wstring>& vecCategoryCode, std::map<std::wstring, int>& mapComponentCount);

    /// Merge前 读取本地增删改的构件id 和version列表
    static  std::map<GmepComponentDirtyFlag, std::map<std::wstring, int>> GetLocalChangedIdList(const std::wstring& projectId);

    /// Merge前 从db3里查找addOrUpdateComponentIdList， 识别出哪些是已有的（updateComponentIdList）， 哪些没有的
    static void GetExistIdListAndNonexistIdIdList(const std::wstring& projectId, const std::map<std::wstring, int>& addOrUpdateComponentIdList,
        std::map<std::wstring, int>& nonexistComponentIdList, std::map<std::wstring, int>& existComponentIdList);

    /// Merge时 清理本地的增删改痕迹，需抛弃本地修改和删除时 
    static bool RemoveDirtyFlagRecords(const std::wstring& projectId, const std::vector<std::wstring>& ToBeDeletedRecordIdVecFromDb3);

    /// Merge后检查重名情况并重命名
    /// 返回被重命名的项的id 和version
    static bool CheckAndRenameDirtyComponents(const std::wstring& projectId, const std::map<std::wstring, int>& modifiedIdMap, 
        const std::map<std::wstring, int>& addedIdMap, std::map<std::wstring, int>& renamedIdMap);
    ///  Merge后, 发送完成功修改项/删除项， 需把本地的dirty flag 置为0
    static bool RemoveDirtyFlagAfterSendModifiedOrDeletedComponents(const std::wstring&projectId, std::map<std::wstring, int> modifiedSuccMap, bool isDelete =false);
    ///  Merge后, 发送完成功新增GAC项， 需把本地的dirty flag 置为0， 并重设id 和name
    static bool UpdateIdNameAfterSendAddedGACComponents(const std::wstring&projectId, std::vector<std::tuple<std::wstring, std::wstring, std::wstring>> uploadedComponents);

    /// 图例族根据企业库id，查表得到 spuId 和resourceId
    static bool GetEnterpriseLegendPlaceholderInfo(const std::wstring & projectID, const std::wstring & idFromEnterprise, std::wstring & resourceId, std::wstring & spuId);

    /// \brief 获取本地库中指定构件的各版本信息
    /// 
    /// \param [IN] projectId 协同项目ID
    /// \param [IN] componentId 构件ID
    /// \param [OUT] componentVersions 所查到的构件各版本数据列表，列表元素为一个元组，元组内各项依次为：version, dirtyFlag, name
    /// \return void
    static void GetComponentVersions(const std::wstring & projectId, const std::wstring & componentId, std::vector<std::tuple<int, int, std::wstring>> &componentVersions);

    /// \brief 检查本地库中是否存在指定构件
    ///
    /// \param [IN] projectId 协同项目ID
    /// \param [IN] componentId 构件ID
    /// \param [OUT] componentOfLatestVersion 若存在，则返回该构件的最新版本数据，为一个元组，元组内各项依次为：version, dirtyFlag, name; 否则，返回一个空元组
    /// \return 若存在，则返回true; 否则，返回false
    static bool CheckComponentExisted(const std::wstring & projectId, const std::wstring & componentId, std::tuple<int, int, std::wstring> &componentOfLatestVersion);

    /// \brief 检查本地库中是否存在指定构件
    ///
    /// \param [IN] projectId 协同项目ID
    /// \param [IN] componentId 构件ID
    /// \return 若存在，则返回true; 否则，返回false
    static bool CheckComponentExisted(const std::wstring & projectId, const std::wstring & componentId,const std::wstring &typeName);

    //ProductLibraryFileName db3路径 
    //projectProduct2DFolder 2d 文件夹的 文件夹路径 用于构造GacFileInfo.m_filePath = projectProduct2DFolder + 数据库中name字段+ .gac
    //projectLegendIds 要查询的图例ID vector
    //vectorPlaceHolderInfo 返回所有查询到的图例信息
    //bool 返回值 成功true 失败false
    static bool SeachPlaceHolderInfo(const std::wstring& ProductLibraryFileName, const std::wstring& projectProduct2DFolder, const std::vector<std::wstring>& projectLegendIds, std::vector<std::tuple<GacFileInfo, std::wstring, int>> &vectorPlaceHolderInfo);

    // 私有化下， 可能需要更新下 构件表中的 Family_2D_Plane_From,Family_2D_FrontBackElevation_From,Family_2D_RightLeftElevation_From,Family_2D_Electric_From 字段
    static bool UpdateComponentPlaceHolderFrom(const std::wstring& dbFilePath,
        const std::map<std::wstring, ComponentInfos>& compMap, const std::map<std::wstring, GmepComponentPlaceHolderInfo>& forceUpdatedResPlaceHolderMap);
};
